#include "gd32l23x.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesPWM.h"


int8_t cTimer1PWMOutInit(void)
{
    timer_parameter_struct timer_initpara = {0};
    timer_oc_parameter_struct timer_ocinitpara = {0};

    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);

    /* TIMERx GPIO */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_10 | GPIO_PIN_11);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_10 | GPIO_PIN_11);

    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_15);
    gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_3);
    gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_10);
    gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_11);

    /* TIMERx configuration */
    timer_deinit(TIMER1);
    timer_initpara.prescaler         = 1 - 1;
    timer_initpara.period            = (SystemCoreClock / 64000) - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_CENTER_BOTH;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_init(TIMER1, &timer_initpara);

    /* configure TIMERx channelx output function */
    timer_ocinitpara.outputstate    = TIMER_CCX_ENABLE;
    timer_ocinitpara.ocpolarity     = TIMER_OC_POLARITY_HIGH;
    timer_channel_output_config(TIMER1, TIMER_CH_0, &timer_ocinitpara);
    timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocinitpara);
    timer_channel_output_config(TIMER1, TIMER_CH_2, &timer_ocinitpara);
    timer_channel_output_config(TIMER1, TIMER_CH_3, &timer_ocinitpara);

    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0, 0);
    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 0);
    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_2, 0);
    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3, 0);
    /* CHx configuration in OC timing mode */
    timer_channel_output_mode_config(TIMER1, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    timer_channel_output_mode_config(TIMER1, TIMER_CH_2, TIMER_OC_MODE_PWM0);
    timer_channel_output_mode_config(TIMER1, TIMER_CH_3, TIMER_OC_MODE_PWM1);

    timer_channel_output_shadow_config(TIMER1, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);
    timer_counter_value_config(TIMER1, 0);
    /* auto-reload preload enable */
    timer_disable(TIMER1);

    return 0;
}

int8_t cTimer2PWMOutInit(void)
{
    timer_parameter_struct timer_initpara = {0};
    timer_oc_parameter_struct timer_ocinitpara = {0};

    rcu_periph_clock_enable(RCU_TIMER2);
    rcu_periph_clock_enable(RCU_GPIOC);

    /* TIMERx GPIO */
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);

    gpio_af_set(GPIOC, GPIO_AF_1, GPIO_PIN_6);
    gpio_af_set(GPIOC, GPIO_AF_1, GPIO_PIN_7);
    gpio_af_set(GPIOC, GPIO_AF_1, GPIO_PIN_8);
    gpio_af_set(GPIOC, GPIO_AF_1, GPIO_PIN_9);

    /* TIMERx configuration */
    timer_deinit(TIMER2);
    timer_initpara.prescaler         = 1 - 1;
    timer_initpara.period            = (SystemCoreClock / 64000) - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_CENTER_BOTH;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_init(TIMER2, &timer_initpara);

    /* configure TIMERx channelx output function */
    timer_ocinitpara.outputstate    = TIMER_CCX_ENABLE;
    timer_ocinitpara.ocpolarity     = TIMER_OC_POLARITY_HIGH;
    timer_channel_output_config(TIMER2, TIMER_CH_0, &timer_ocinitpara);
    timer_channel_output_config(TIMER2, TIMER_CH_1, &timer_ocinitpara);
    timer_channel_output_config(TIMER2, TIMER_CH_2, &timer_ocinitpara);
    timer_channel_output_config(TIMER2, TIMER_CH_3, &timer_ocinitpara);

    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 0);
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, 0);
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_2, 0);
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_3, 0);
    /* CHx configuration in OC timing mode */
    timer_channel_output_mode_config(TIMER2, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_2, TIMER_OC_MODE_PWM0);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_3, TIMER_OC_MODE_PWM1);

    timer_channel_output_shadow_config(TIMER2, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER2);
    timer_counter_value_config(TIMER2, 0);
    /* auto-reload preload enable */
    timer_disable(TIMER2);

    return 0;
}

/* 定时器时钟频率 */
#define TIMER_CLOCK_VALUE        64000000
/* 死区时间:x·ns */
#define TIMER_DEADTIME_VALUE     400

void vTimerxChannel0lPlusSet(uint32_t timer_periph, int32_t iPlus)
{
    int32_t iPlusHigh;

//    /* 防止超调 */
//    iPlus = (iPlus > TIMER_CAR(timer_periph)) ? TIMER_CAR(timer_periph) :((iPlus < 0) ? 0 : iPlus);

    /* 主动加上死区时间 */
    iPlusHigh = iPlus - ((TIMER_CLOCK_VALUE / 1000000) * TIMER_DEADTIME_VALUE / 1000);
    iPlusHigh = (iPlusHigh < 0) ? 0 : iPlusHigh;

    __disable_irq();
    if(iPlus > TIMER_CH1CV(timer_periph))
    {
        TIMER_CH1CV(timer_periph) = iPlus;
        TIMER_CH0CV(timer_periph) = iPlusHigh;
    }
    else
    {
        TIMER_CH0CV(timer_periph) = iPlusHigh;
        TIMER_CH1CV(timer_periph) = iPlus;
    }
    __enable_irq();
}

void vTimerxChannel23PlusSet(uint32_t timer_periph, int32_t iPlus)
{
    int32_t iPlusHigh;

//    /* 防止超调 */
//    iPlus = (iPlus > TIMER_CAR(timer_periph)) ? TIMER_CAR(timer_periph) :((iPlus < 0) ? 0 : iPlus);

    /* 主动加上死区时间 */
    iPlusHigh = iPlus - ((TIMER_CLOCK_VALUE / 1000000) * TIMER_DEADTIME_VALUE / 1000);
    iPlusHigh = (iPlusHigh < 0) ? 0 : iPlusHigh;

    __disable_irq();
    if(iPlus > TIMER_CH3CV(timer_periph))
    {
        TIMER_CH3CV(timer_periph) = iPlus;
        TIMER_CH2CV(timer_periph) = iPlusHigh;
    }
    else
    {
        TIMER_CH2CV(timer_periph) = iPlusHigh;
        TIMER_CH3CV(timer_periph) = iPlus;
    }
    __enable_irq();
}
